// 类：使用 class 关键字定义，定义时可以使用 extends 继承一个父类
// 重点：类的访问类型（即定义类中的属性和方法的关键字，主要有如下三个）：
// public：公共的，被修饰的字段在类的内部和外部均可以被访问(默认访问类型)
// private: 私有的，被修饰的字段只能在当前类中使用，在外部和子类中均不能访问
// protected: 受到一定保护的，被修饰的字段只能在当前类和子类中访问，在类和子类的外部无法访问
class Preson {
  public name: string
  // private name: string
  // protected name: string
  sayHello() {
    console.log(this.name + ' 你好啊！')
  }
}
// 定义一个 Son 的子类让它继承自 Preson 类
class Son extends Preson {
  sayBey() {
    // 在 Son 中也访问不到 Preson 父类中使用 private 修饰的属性和方法
    // 在 Son 中可以访问到 Preson 父类中使用 protected 修饰的属性和方法
    console.log(this.name + ' 再见！')
  }
  // 在 Son 子类中对 Preson 父类的 sayHello 方法进行重写
  sayHello() {
    console.log(this.name + 'Hi Hello!')
    // 方法重写后如果需要访问父类中的该方法可以使用 super 关键字进行访问
    console.log(super.sayHello())
  }
}
const son = new Son()
// 因为 Preson 中的 name 是使用 public 关键字进行修饰的所以在外部是可以正常访问的
// preson.name = '小明'
// 如果把访问类型改成 private/protected 则在类的外部就不能访问到该属性或方法了
son.name = '小明'
son.sayHello()
son.sayBey()

// 补充：类的构造函数
// 定义一个父类
class Father {
  name: string
  // 每个类都自带一个 constructor 构造函数
  constructor(name: string) {
    this.name = name
  }
}
// 定义一个子类继承自 Father 类
class Thisme extends Father {
  // 注：这里的 public age 的写法和 Father 类中定义 name 属性是一样的效果，这里相当于简写
  constructor(name: string, public age: number) {
    // 注意：在子类（又叫 派生类）中的 constructor() 构造函数中必须要调用 super() 方法，不然会报错!!
    super(name)
  }
}

// const demo = new Father('小唐')
const demo = new Thisme('小唐', 18)
console.log(demo.name, demo.age)
